<script setup lang="ts">
import { onMounted, nextTick, ref, reactive, watch } from "vue";
import type { PropType } from "vue";
import * as icons from "@ant-design/icons-vue";
import { CloseOutlined, ReloadOutlined, ArrowLeftOutlined, ArrowRightOutlined,
  ColumnWidthOutlined, DeleteOutlined, ExportOutlined, RightOutlined, LeftOutlined } from "@ant-design/icons-vue";
import { VueDraggableNext } from "vue-draggable-next";
import { webxRouteTabsStore } from "../../store/webxRouteTabs.store";
import type { WebxRouteTab } from "../../hooks";
import { useWebxRouteTabs } from "../../hooks";
import { useRouter } from "vue-router";
import EventEmitUtil from "../../utils/event-emit.util";

defineOptions({ name:"WebxRouteTabs" });
/**
 * changeAfter：激活的tab改变时触发，返回 tab
 * */
const emits = defineEmits(["changeAfter"]);
const props = defineProps({
  // 主页，不可被关闭，默认激活
  dashboard:{ type:Object as PropType<WebxRouteTab>, default:() => ({}) }
});

const router = useRouter();
const routeTabsStore = webxRouteTabsStore();
const { openTarget, refresh, addTab, closeCurrent, getPrevTab, getActiveTab, closeLeft, closeRight, closeOther, closeAll } = useWebxRouteTabs({ router });
// 拖拽元素父级容器
const draggableWrapRef = ref();
// 拖拽元素
const draggableContentRef = ref();
// 拖拽子元素
const draggableItemsRef = ref();
// 拖拽排序控制
const scrollData = reactive({
  // 是否渲染左箭头
  leftArrow:false,
  // 是否渲染右箭头
  rightArrow:false,
  // 是否滚动到最左边
  isLeft:true,
  // 是否滚动到最右边
  isRight:true,
  async set(){
    await nextTick();
    setTimeout(() => {
      // 设置左右箭头的显示时机
      scrollData.rightArrow = draggableContentRef.value?.$el?.offsetWidth > draggableWrapRef.value?.offsetWidth;
      scrollData.leftArrow = draggableContentRef.value?.$el?.offsetWidth > draggableWrapRef.value?.offsetWidth;
    }, 300)
  },
  // 获取gap尺寸
  getDraggableContentGap(){
    if(!draggableContentRef.value?.$el) return 0;
    const draggableContentStyle = getComputedStyle(draggableContentRef.value.$el);
    const draggableContentGap = Number(draggableContentStyle.gap.replace("px",""));
    return isNaN(draggableContentGap) ? 0 : draggableContentGap;
  },
  // 点击右箭头
  clickRight(){
    // 计算父容器的内容区域边界（考虑边框和滚动条）
    const parentRect = draggableWrapRef.value.getBoundingClientRect();
    // 获取间隔槽
    const draggableContentGapReal = scrollData.getDraggableContentGap();
    const parentContentLeft = parentRect.left + draggableWrapRef.value.clientLeft;
    const parentContentRight = parentContentLeft + draggableWrapRef.value.clientWidth;

    // 寻找可视区域内最后一个可见的子元素
    let lastVisibleSon = null;
    for (let i = 0; i < draggableItemsRef.value.length; i++) {
      const sonRect = draggableItemsRef.value[i].getBoundingClientRect();

      if (sonRect.left < parentContentRight && sonRect.right > parentContentLeft) {
        // 判断元素是否至少部分可见
        lastVisibleSon = draggableItemsRef.value[i];
      } else if (sonRect.left >= parentContentRight) {
        // 如果元素完全在可视区域右侧，提前结束循环
        break;
      }
    }

    // 处理找到的最后一个可见元素
    if (lastVisibleSon) {
      const sonRect = lastVisibleSon.getBoundingClientRect();

      // 检查元素是否完全可见
      if (Math.round(sonRect.right) > parentContentRight) {
        // 未完全显示：滚动使元素完整显示
        const scrollDistance = sonRect.right - parentContentRight;
        draggableWrapRef.value.scrollLeft += scrollDistance + draggableContentGapReal;
      } else {
        // 已完全显示：滚动到下一个元素
        const nextSon = lastVisibleSon.nextElementSibling;
        if (nextSon) {
          draggableWrapRef.value.scrollLeft += nextSon.offsetWidth + draggableContentGapReal;
        }
      }
    }

    scrollData.setScrollStatus();
  },
  // 点击左箭头
  clickLeft(){
    // 间隔槽
    const draggableContentGapReal = scrollData.getDraggableContentGap();
    const parentRect = draggableWrapRef.value.getBoundingClientRect();
    const parentLeft = parentRect.left + draggableWrapRef.value.clientLeft;

    // 查找第一个可见元素
    let firstVisibleSon = null;
    for (let i = 0; i < draggableItemsRef.value.length; i++) {
      const sonRect = draggableItemsRef.value[i].getBoundingClientRect();

      // 判断元素是否至少部分可见
      if (sonRect.right > parentLeft && sonRect.left < parentRect.right) {
        firstVisibleSon = draggableItemsRef.value[i];
        break;
      }
    }

    if(!firstVisibleSon) return;
    const sonRect = firstVisibleSon.getBoundingClientRect();

    // 检查元素左侧是否被裁剪
    let scrollLeft = 0;
    if (Math.round(sonRect.left) < parentLeft) {
      // 未完全显示：滚动使元素完整显示
      scrollLeft = parentLeft - sonRect.left + draggableContentGapReal;
    } else {
      // 已完全显示：滚动到前一个元素
      const prevSon = firstVisibleSon.previousElementSibling;
      if (prevSon) {
        const prevRect = prevSon.getBoundingClientRect();
        scrollLeft = prevRect.width + draggableContentGapReal;
      }
    }
    draggableWrapRef.value.scrollBy({
      left: -scrollLeft,
      behavior: "smooth"
    });

    scrollData.setScrollStatus();
  },
  // 设置激活页签的完整显示
  setActiveTabFullVisible(){
    // 获取间隔尺寸
    const draggableContentGapReal = scrollData.getDraggableContentGap();

    // 获取当前激活的页签
    const activeTab = getActiveTab();
    const activeTabIndex = routeTabsStore.dataSource.findIndex(t => t.key === activeTab.key);
    const activeDraggableItemRef = draggableItemsRef.value?.[activeTabIndex] || null;
    // 计算元素边界
    const activeDraggableItemRect = activeDraggableItemRef?.getBoundingClientRect() || {};

    // 计算父容器边界
    const parentRect = draggableWrapRef.value?.getBoundingClientRect()|| {};
    const parentLeft = parentRect.left + (draggableWrapRef.value?.clientLeft || 0);
    const parentRight = parentLeft + (draggableWrapRef.value?.clientWidth || 0);

    // 检测显示状态
    const isLeftVisible = Math.floor(activeDraggableItemRect.left) >= Math.floor(parentLeft);
    const isRightVisible = Math.floor(activeDraggableItemRect.right) <= Math.floor(parentRight);

    if (!(isLeftVisible && isRightVisible)) {
      if (!isLeftVisible) {
        // 左侧被遮挡
        const scrollDistance = (activeDraggableItemRef?.offsetLeft || 0) - draggableContentGapReal;
        draggableWrapRef.value?.scrollTo({
          left: -scrollDistance,
          behavior: "smooth"
        });
      } else {
        // 右侧被遮挡
        const scrollDistance = (activeDraggableItemRef?.offsetLeft || 0)
            + (activeDraggableItemRef?.offsetWidth || 0)
            - (draggableWrapRef.value?.clientWidth || 0)
            + draggableContentGapReal;
        draggableWrapRef.value?.scrollTo({
          left: scrollDistance,
          behavior: "smooth"
        });
      }
    }

    scrollData.setScrollStatus();
  },
  // 获取滚动状态
  setScrollStatus(){
    setTimeout(() => {
      // 滚到最左边
      scrollData.isLeft = draggableWrapRef.value?.scrollLeft <= 0;
      // 滚到最右边
      scrollData.isRight = draggableWrapRef.value?.scrollLeft + draggableWrapRef.value?.clientWidth >= draggableWrapRef.value?.scrollWidth;
    }, 300)
  }
});

// 获取图标属性
const getIcon = (tab:WebxRouteTab) => {
  const [type, iconName] = tab.icon?.split(":") || ["antdv", "TagOutlined"];
  const isAntdv = type === "antdv";
  return { isAntdv, iconName };
};

// 控制下拉菜单的显隐
const getMenuItemVisible = (tab:WebxRouteTab, tabIndex:number) => {
  // 关闭当前
  const closeCurrent = tab.closable;
  // 关闭左侧
  const closeLeft = !!routeTabsStore.dataSource.filter((t,ti) => ti < tabIndex && t.closable).length;
  // 关闭右侧
  const closeRight = !!routeTabsStore.dataSource.filter((t,ti) => ti > tabIndex && t.closable).length;
  // 关闭其他
  const closeOther = !!routeTabsStore.dataSource.filter((t,ti) => ti !== tabIndex && t.closable).length;
  // 关闭全部
  const closeAll = !!routeTabsStore.dataSource.filter((t,ti) => t.closable).length;

  return { closeCurrent, closeLeft, closeRight, closeOther, closeAll };
};

// 菜单点击
const clickMenuItem = async (tab:WebxRouteTab, menuItemType:string) => {
  if(menuItemType === "click") { // 切换激活的页签
    addTab(tab);
  } else if(menuItemType === "openTarget") { // 新窗口打开页签
    openTarget(tab);
  } else if(menuItemType === "refresh") { // 刷新页签
    if(!tab.active) addTab(tab);
    await nextTick();
    refresh();
  } else if(menuItemType === "closeCurrent") { // 关闭当前
    if(!tab.closable) return;
    const prevTab = getPrevTab(tab);
    closeCurrent(tab);
    addTab(prevTab);
  } else if(menuItemType === "closeLeft") { // 关闭左侧
    closeLeft(tab);
  } else if(menuItemType === "closeRight") { // 关闭右侧
    closeRight(tab);
  } else if(menuItemType === "closeOther") { // 关闭其他
    closeOther(tab);
  } else if(menuItemType === "closeAll") { // 关闭全部
    closeAll();
    addTab(props.dashboard);
  }
}

watch(() => routeTabsStore.dataSource,async () => {
  // 设置滚动属性
  await scrollData.set();
}, { immediate: true });

// 监听激活页签发生改变，触发changeAfter
EventEmitUtil.on("ROUTE_TABS:CHANGE_AFTER", (routeTab: WebxRouteTab) => {
  // 抛出changeAfter事件
  emits("changeAfter", routeTab);
  // 设置当前激活的页签完整显示
  scrollData.setActiveTabFullVisible();
  // 设置滚动状态
  scrollData.setScrollStatus();
})

onMounted(() => {
  // 添加主页
  if(!routeTabsStore.dataSource.length) {
    addTab(props.dashboard);
  }
  // 页面尺寸发生改变时设置
  window.addEventListener("resize", async () => {
    await scrollData.set();
  })
})
</script>

<template>
  <div class="webx-route-tabs py-2" v-if="routeTabsStore.dataSource.length > 1">
    <div class="flex items-center gap-2">
      <AButton class="flex-shrink-0" size="small" :disabled="scrollData.isLeft" @click="scrollData.clickLeft" v-if="scrollData.leftArrow"><LeftOutlined /></AButton>
      <div class="flex-1 overflow-auto" ref="draggableWrapRef">
        <VueDraggableNext class="flex gap-2 w-max" ref="draggableContentRef" v-model="routeTabsStore.dataSource">
          <div class="rounded" ref="draggableItemsRef" :class="{ 'bg-gray-200': !tab.active }" v-for="(tab, tabIndex) in routeTabsStore.dataSource" :key="tab.key">
            <ADropdown :trigger="['contextmenu']">
              <ACheckableTag :checked="tab.active" class="mr-0 py-0.5" closable :bordered="false"
                             @click="clickMenuItem(tab, 'click')"
                             @dblclick="clickMenuItem(tab, 'closeCurrent')">
                <div class="flex items-center gap-1">
                  <div class="tag-icon">
                    <component v-if="getIcon(tab).isAntdv" :is="icons[getIcon(tab).iconName]" />
                  </div>
                  <div class="tag-title">{{ tab.title }}</div>
                  <div class="tag-close" v-if="tab.closable" @click="clickMenuItem(tab, 'closeCurrent')">
                    <CloseOutlined />
                  </div>
                </div>
              </ACheckableTag>
              <template #overlay>
                <AMenu>
                  <!--              <AMenuItem key="openTarget" @click="clickMenuItem(tab, 'openTarget')"><ExportOutlined /> 新窗口打开</AMenuItem>-->
                  <AMenuItem key="refresh" @click="clickMenuItem(tab, 'refresh')"><ReloadOutlined /> 刷新页签</AMenuItem>
                  <AMenuItem key="closeCurrent" @click="clickMenuItem(tab, 'closeCurrent')" v-if="getMenuItemVisible(tab, tabIndex).closeCurrent"><CloseOutlined /> 关闭当前</AMenuItem>
                  <AMenuItem key="closeLeft" @click="clickMenuItem(tab, 'closeLeft')" v-if="getMenuItemVisible(tab, tabIndex).closeLeft"><ArrowLeftOutlined /> 关闭左侧</AMenuItem>
                  <AMenuItem key="closeRight" @click="clickMenuItem(tab, 'closeRight')" v-if="getMenuItemVisible(tab, tabIndex).closeRight"><ArrowRightOutlined /> 关闭右侧</AMenuItem>
                  <AMenuItem key="closeOther" @click="clickMenuItem(tab, 'closeOther')" v-if="getMenuItemVisible(tab, tabIndex).closeOther"><ColumnWidthOutlined /> 关闭其他</AMenuItem>
                  <AMenuItem key="closeAll" @click="clickMenuItem(tab, 'closeAll')" v-if="getMenuItemVisible(tab, tabIndex).closeAll"><DeleteOutlined /> 关闭全部</AMenuItem>
                </AMenu>
              </template>
            </ADropdown>
          </div>
        </VueDraggableNext>
      </div>
      <AButton class="flex-shrink-0" size="small" :disabled="scrollData.isRight" @click="scrollData.clickRight" v-if="scrollData.rightArrow"><RightOutlined /></AButton>
    </div>
  </div>
</template>

<style scoped lang="less">
::-webkit-scrollbar {
  display: none;
}
</style>